package io.plus.engine.server;

import io.plus.engine.pulse.ReadCompletionHandler;
import io.plus.engine.pulse.collections.IpBlackLists;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import tool.plus.Clock;

import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

@Data
@Slf4j
public class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Server> {


    public AcceptCompletionHandler() {
    }

    @Override
    public void completed(AsynchronousSocketChannel asynchronousSocketChannel, Server server) {
        try {
            ServerConfiguration serverConfiguration = server.getServerConfiguration();
            InetSocketAddress inetSocketAddress = (InetSocketAddress) asynchronousSocketChannel.getRemoteAddress();
            String clientIp = inetSocketAddress.getHostString();
            if (IpBlackLists.isInBlacklist(serverConfiguration, clientIp)) {
                log.info("{}在黑名单中, {}", clientIp, serverConfiguration.getName());
                asynchronousSocketChannel.close();
                return;
            }
            //
            asynchronousSocketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
            asynchronousSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
            asynchronousSocketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 64 * 1024);
            asynchronousSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);
            //

            ServerAsynchronousSocketChannelContext serverAsynchronousSocketChannelContext = new ServerAsynchronousSocketChannelContext(serverConfiguration, asynchronousSocketChannel);
            serverAsynchronousSocketChannelContext.setServerNode(server.getServerNode());
            serverAsynchronousSocketChannelContext.asynchronousSocketChannelState.setTimeFirstConnected(Clock.currentTimeMillis);
            serverAsynchronousSocketChannelContext.setClosed(false);//public boolean isClosed = true;
            //
            serverConfiguration.ips.bind(serverAsynchronousSocketChannelContext);


            if (!server.isWaitingStop()) {
                ReadCompletionHandler readCompletionHandler = serverAsynchronousSocketChannelContext.getReadCompletionHandler();
                ByteBuffer readByteBuffer = readCompletionHandler.getReadByteBuffer();
                readByteBuffer.position(0);
                readByteBuffer.limit(readByteBuffer.capacity());
                asynchronousSocketChannel.read(readByteBuffer, readByteBuffer, readCompletionHandler);
            }
        } catch (Throwable e) {
            log.error("", e);
        } finally {
            if (server.isWaitingStop()) {
                log.info("{}即将关闭服务器，不再接受新请求", server.getServerNode());
            } else {
                AsynchronousServerSocketChannel serverSocketChannel = server.getAsynchronousServerSocketChannel();
                serverSocketChannel.accept(server, this);
            }
        }
    }

    @Override
    public void failed(Throwable throwable, Server server) {
        AsynchronousServerSocketChannel asynchronousServerSocketChannel = server.getAsynchronousServerSocketChannel();
        asynchronousServerSocketChannel.accept(server, this);

        log.error("[" + server.getServerNode() + "]监听出现异常", throwable);

    }

}
